package xnj.lazydog.btcontroller.ControlViews.ControlViews;

import android.app.AlertDialog;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import xnj.lazydog.btcontroller.Bluetooth.BlueToothMaster;
import xnj.lazydog.btcontroller.ControlViews.CSVFile;
import xnj.lazydog.btcontroller.ControlViews.ControlView;
import xnj.lazydog.btcontroller.ControlViews.Value;
import xnj.lazydog.btcontroller.ControlViews.ViewOptions;
import xnj.lazydog.btcontroller.MyViews.IDBitmap;
import xnj.lazydog.btcontroller.R;

public class ControlPlot extends ControlElement {

    boolean menu_showing = false;
    boolean data_following = true;
    boolean data_recording = true;

    Bitmap []tools = new Bitmap[4];
    Bitmap []scaled_tools = new Bitmap[4];

    int [] colors = new int[]{0xffff5436,0xfffff445,0xff56ff62,0xff56e1ff,0xff5275ff,0xffff56f5};

    int BUFFER_SIZE = 10000;
    float [][] wave_buffer = new float[6][BUFFER_SIZE];

    int time=0;

    float menu_anim = 0;
    final  float TEETH_RATIO = 0.012f;
    final  float TEETH_MIN_MM = 0.6f;
    final  float TEETH_NUMBER_RATIO = 1.5f; // 字体高度相对于teeth的长度的比例

    float teeth_pix;
    float teeth_min;
    float teeth_width_pix;
    float teeth_number_pix;
    float teeth_number_offset_pix;

    DecimalFormat decimalFormat;

    Paint label_p;

    public ControlPlot (ViewOptions options)
    {
        super(options);
        label_p = new Paint();
        label_p.setAntiAlias(true);
        decimalFormat = new DecimalFormat("##.##");
        tools[0] = BitmapFactory.decodeResource(ControlView.resources,R.drawable.toy_play);
        tools[1] = BitmapFactory.decodeResource(ControlView.resources,R.drawable.toy_shotcut);
        tools[2] = BitmapFactory.decodeResource(ControlView.resources,R.drawable.toy_left);
        tools[3] = BitmapFactory.decodeResource(ControlView.resources,R.drawable.toy_right);

        setMsPerData(options.ms_per_data);

        settingsAfterLink = false;
    }


    @Override
    public void showSettingsDialog(Context context) {

        final EditText on_edit;
        Button ok;

        String str;
        final AlertDialog dialog;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        View layout = LayoutInflater.from(context).inflate(R.layout.toy_settings_plot_time_unit,null);
        builder.setView(layout);
        dialog = builder.create();
        if(dialog.getWindow()!=null)
            dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        on_edit = layout.findViewById(R.id.on_edit);
        ok = layout.findViewById(R.id.button);

        if(options.ms_per_data<=0)
            options.ms_per_data = 10;
        str = decimalFormat.format(options.ms_per_data);


        on_edit.setText(str);
        on_edit.setSelection(str.length());

        ok.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Value value = getNumber(on_edit.getText().toString());
                if(value.type==0)
                {
                    on_edit.setText("10");
                    on_edit.setSelection(2);
                    return;
                }else
                {
                    options.ms_per_data = value.getFloat();
                }

                dialog.dismiss();
            }
        });
        dialog.show();

    }

    private static final String TAG = "ControlPlot";

    float getRegulatedSegmentDiv(int initial,float highest,float lowest)
    {
        if(initial<=0)
            initial=1;
        float div = (highest-lowest)/initial;

        float a,b=1;

        float [] c = new float[]{1,2,5,10};
        float [] d = new float[4];
        float min;
        int min_index=0;
        while (div<1)
        {
            div*=10;
            b*=0.1f;
        }

        while (div>10)
        {
            div*=0.1f;
            b*=10;
        }
        a = div;
        min = 100;
        for(int i=0;i<d.length;i++)
        {
            d[i] = Math.abs((a/c[i])-1);
            if(d[i]<min)
            {
                min = d[i];
                min_index = i;
            }
        }
        ///Log.w(TAG, "getRegulatedSegmentDiv:"+a+"   "+c[min_index]+"  "+(c[min_index]*b));
        return c[min_index]*b;
    }

    final int MIN_SEGMENT = 4;
    final int MAX_SEGMENT = 12;

    float[] getTeethValues(float range_mm,float div_mm,float bottom_value,float top_value)
    {
        if(top_value<bottom_value) {
            Log.e(TAG, "topValue should not be littler than bottomValue");
            return new float[0];
        }
        int seg =  (int)(range_mm/div_mm);
        if(seg<MIN_SEGMENT)
            seg = MIN_SEGMENT;
        if(seg>MAX_SEGMENT)
            seg = MAX_SEGMENT;

        float div = getRegulatedSegmentDiv(seg,top_value,bottom_value);

        int start;
        int stop;

        if(bottom_value>0)
            start = (int)(bottom_value/div);
        else
            start = (int)(bottom_value/div-1);

        if(top_value>0)
            stop = (int)(top_value/div);
        else
            stop = (int)(top_value/div-1);

        if(stop>start)
        {
            float []values = new float[stop-start];

            for(int i=0;i<values.length;i++)
            {
                values[i] = (start+1+i)*div;
               // Log.w(TAG, "----"+values[i]);
            }
            return values;
        }else
        {
            return new float[0];
        }
    }


    /**  由输入的时间索引值，根据时间偏移量、时间缩放系数、控件像素宽度等得出相应的像素值
     *   时间缩放系数的单位为 整个窗口中数据点个数，即时间单位的个数
     * @param time
     * @return
     */
    float time2pix(float time)
    {
        return  teeth_pix-w_half+((time_offset_d-time)/options.threshold)*w_range;
    }
    float value2pix(float value)
    {
        return h_half-teeth_pix-h_range*(value-options.off_value)/(options.on_value-options.off_value);
    }
    float ratio2time(float ratio)
    {
        return time_offset_d-options.threshold*ratio;
    }
    float ratio2value(float ratio)
    {
        return  options.on_value-(options.on_value-options.off_value)*ratio;
    }

    float time_offset,time_offset_d;
    float [] value_teeth;
    float [] time_teeth;

    float teeth_pos;
    String number;

    float teeth_text_size;
    float teeth_text_anim;
    String number2;
    float number_mm1,number_mm2;

    float teeth_item_alpha;
    float teeth_item_k = 0.5f;

    void drawTeeth(Canvas  canvas)
    {
        p.setColor(0xffffffff);
        value_teeth =  getTeethValues(options.h,8,options.off_value,options.on_value);

        float dataPerSec = 1/secPerData;

        float sec,sec_1;

        sec = time_offset_d*secPerData;
        sec_1 = (time_offset_d-options.threshold)*secPerData;

        number = decimalFormat.format(sec);
        number2 = decimalFormat.format(sec_1);

        number_mm1 = number.length()*ControlView.pix2MM(teeth_number_pix);
        number_mm2 = number2.length()*ControlView.pix2MM(teeth_number_pix);
        if(number_mm2>number_mm1)
            number_mm1 =number_mm2;

        number_mm1 = 8f;


        time_teeth = getTeethValues(options.w,number_mm1,sec_1,sec);
        p.setStrokeWidth(teeth_width_pix);

        canvas.drawLine(teeth_pix-w_half,-h_half,teeth_pix-w_half,h_half-teeth_pix,p);
        canvas.drawLine(teeth_pix-w_half,h_half-teeth_pix,w_half,h_half-teeth_pix,p);

        for(int i=0;i<value_teeth.length;i++)
        {
            teeth_pos = value2pix(value_teeth[i]);
            canvas.drawLine(-w_half,teeth_pos,-w_half+teeth_pix,teeth_pos,p);
        }

        for(int i=0;i<time_teeth.length;i++)
        {
            teeth_pos = time2pix(time_teeth[i]*dataPerSec);
            canvas.drawLine(teeth_pos,h_half-teeth_pix,teeth_pos,h_half,p);
        }


        if(menu_anim>0.05f) {
            teeth_text_anim = (1-menu_anim)*teeth_number_pix*4;


            if (Math.abs(teeth_number_pix - teeth_text_size) > 5) {
                teeth_text_size = (int) teeth_number_pix;
                p.setTextSize(teeth_text_size);
            }
            p.setTextAlign(Paint.Align.LEFT);
            for (int i = 0; i < value_teeth.length; i++) {

                teeth_pos = value2pix(value_teeth[i]);

                if(teeth_pos>0)
                {
                    teeth_item_alpha = Math.abs(teeth_pos-h_half+teeth_pix)/teeth_number_pix*teeth_item_k;
                }else
                {
                    teeth_item_alpha = Math.abs(teeth_pos+h_half)/teeth_number_pix*teeth_item_k;
                }
                if(teeth_item_alpha>1)
                    teeth_item_alpha = 1;

                p.setARGB((int) (255 * menu_anim*teeth_item_alpha), 255, 255, 255);
                number = decimalFormat.format(value_teeth[i]);

                canvas.drawText(number, teeth_pix - w_half + teeth_number_offset_pix-teeth_text_anim, teeth_pos + teeth_number_offset_pix, p);
            }
            p.setTextAlign(Paint.Align.CENTER);
            for (int i = 0; i < time_teeth.length; i++) {
                teeth_pos = time2pix(time_teeth[i]*dataPerSec);

                if(teeth_pos>0)
                {
                    teeth_item_alpha = Math.abs(teeth_pos-w_half)/teeth_number_pix*teeth_item_k;
                }else
                {
                    teeth_item_alpha = Math.abs(teeth_pos+w_half-teeth_pix)/teeth_number_pix*teeth_item_k;
                }
                if(teeth_item_alpha>1)
                    teeth_item_alpha = 1;

                p.setARGB((int) (255 * menu_anim*teeth_item_alpha), 255, 255, 255);
                number = decimalFormat.format(time_teeth[i]);
                canvas.drawText(number, teeth_pos, -teeth_pix + h_half - teeth_number_offset_pix+teeth_text_anim, p);
            }
        }
    }

    float [] extractPoints(int buffer_index,float start_time,float stop_time,float div)
    {
        float v;
        int points = (int)((stop_time-start_time)/div)+1;
        float [] wave = new float[points];

        float data_index_f = stop_time;
        int data_index ;
        int int_index;
        int data_index_pre;
        ////  1、node_div 节点之间的像素距离 2、points 曲线的节点数 3、节点数据量div。
        float pre_float;
        for(int i=0;i<points;i++)
        {
            int_index = ((int)data_index_f);
            pre_float = data_index_f-int_index;
            if(pre_float<0)
                pre_float=0;
            data_index = int_index%BUFFER_SIZE;
            if(data_index<0)
                data_index +=BUFFER_SIZE;
            data_index_pre = data_index-1;
            if(data_index_pre<0)
                data_index_pre+=BUFFER_SIZE;
            v = wave_buffer[buffer_index][data_index]*(pre_float)+wave_buffer[buffer_index][data_index_pre]*(1-pre_float);
            wave[i]= v;
            data_index_f-=div;
        }

        return wave;
    }


    float [] extractWave(int buffer_index,float start_time,float stop_time,float div)
    {
        float v;
        int points = (int)((stop_time-start_time)/div)+1;

        int points2 = points*2;
        int points4 = points*4-4;
        float node_div = w_range/points;
        float x = teeth_pix-w_half+teeth_width_pix;
        float [] wave = new float[points*2];
        float data_index_f = stop_time;
        int data_index ;
        int int_index;
        int data_index_pre;
        ////  1、node_div 节点之间的像素距离 2、points 曲线的节点数 3、节点数据量div。
        float pre_float;
        for(int i=0;i<points2;i+=2)
        {

            int_index = ((int)data_index_f);
            pre_float = data_index_f-int_index;

            if(pre_float<0)
                pre_float=0;

            data_index = int_index%BUFFER_SIZE;

            if(data_index<0)
                data_index +=BUFFER_SIZE;

            data_index_pre = data_index-1;

            if(data_index_pre<0)
                data_index_pre+=BUFFER_SIZE;

            v = wave_buffer[buffer_index][data_index]*(pre_float)+wave_buffer[buffer_index][data_index_pre]*(1-pre_float);



            wave[i] = x;
            wave[i+1]= value2pix(v);
            x+=node_div;
            data_index_f-=div;
        }

        float [] w = new float[points*4];
        int j=0;
        for(int i=0;i<points4;i+=4)
        {
            w[i] = wave[j];
            w[i+1] = wave[j+1];
            w[i+2] = wave[j+2];
            w[i+3] = wave[j+3];
            j+=2;
        }

        return w;
    }


    float LINE_DIV_MM = 0.3f;
    float node_data_volume;   // 每一个节点包含的数据量
    float node_num;           // 画面中曲线节点的数量

    float [][] waves = new float[6][];

    public void drawWaves(Canvas canvas) {
        node_num = options.w * (w_pix - teeth_pix) / (w_pix * LINE_DIV_MM);
        node_data_volume = options.threshold / node_num;

        p.setStrokeWidth(teeth_width_pix * 0.6f);
        for (int i = 0; i < 6; i++) {
            p.setColor(colors[i]);
            if (linkedValues[i] != null) {
                waves[i] = extractWave(i, time_offset_d - options.threshold, time_offset_d, node_data_volume);
                canvas.drawLines(waves[i], p);
            }
        }

        //Log.w(TAG, "drawWaves "+node_num+"  "+node_data_volume);
    }

    float w_half;
    float h_half;
    float w_range;
    float h_range;

    //// 数据标签
    float LABEL_WIDTH_RATIO = 0.2f;
    float LABEL_Y_RATIO = -0.4f;
    float LABEL_X_RATIO = -0.33f;
    float label_width;
    float label_y;
    float label_height;
    float label_x;

    //// 工具栏
    float TOOLBAR_WIDTH_RATIO = 0.15f;
    float TOOL_BMP_RATIO = 0.12f;
    float TOOLBAR_HEIGHT_RATIO = 0.8f;


    float toolbar_width;
    float toolbar_height;
    float toolbar_bmp_pix;
    float toolbar_bmp_pix_half;
    float toolbar_x;
    float toolbar_y;


    float h_bmp_pix;
    @Override
    public void onSizeChanged() {

        rectF.right = w_pix*0.5f;
        rectF.left = -rectF.right;
        rectF.bottom = h_pix*0.5f;
        rectF.top = -rectF.bottom;

        w_half = w_pix*0.5f;
        h_half = h_pix*0.5f;

        teeth_pix = (w_pix+h_pix)*TEETH_RATIO;
        teeth_min = ControlView.mm2Pix(TEETH_MIN_MM);
        if(teeth_pix<teeth_min)
            teeth_pix = teeth_min;
        teeth_width_pix = teeth_pix*0.3f;
        teeth_number_pix = teeth_pix*TEETH_NUMBER_RATIO;
        teeth_number_offset_pix = teeth_number_pix*0.366f;

        w_range = w_pix-teeth_pix;
        h_range = h_pix-teeth_pix;

        label_width = w_pix*LABEL_WIDTH_RATIO;

        label_x = w_pix*LABEL_X_RATIO;
        label_height = teeth_number_pix*1.2f;
        label_y = -h_half+label_height*0.25f;

        toolbar_width = TOOLBAR_WIDTH_RATIO*w_pix;
        toolbar_height = TOOLBAR_HEIGHT_RATIO*h_pix;

        toolbar_x = w_half-toolbar_width;
        toolbar_y = -toolbar_height*0.5f;


        toolbar_bmp_pix = w_pix*TOOL_BMP_RATIO;

        h_bmp_pix = h_pix*0.18f;

        if(toolbar_bmp_pix>h_bmp_pix)
            toolbar_bmp_pix = h_bmp_pix;

        toolbar_bmp_pix_half = toolbar_bmp_pix*0.5f;

        for(int i=0;i<4;i++)
        {
            scaled_tools[i] = Bitmap.createScaledBitmap(tools[i],(int)toolbar_bmp_pix,(int)toolbar_bmp_pix,true);
        }

    }

    RectF label_rect = new RectF();

    void drawLabels(Canvas canvas,boolean rect)
    {
        int col,row;
        int a = (int)(menu_anim*255);
        int value_index=0;

        canvas.save();
        canvas.translate(0,label_height*3*(menu_anim-0.9f));


        //p.setColor(0xff444444);

        if(rect) {
            p.setColor(0xffffffff);
            p.setAlpha(a);
            label_rect.left = label_x - label_width * 0.15f;
            label_rect.top = -h_half;
            label_rect.right = label_x + label_width * 3;
            label_rect.bottom = label_y + label_height * 2.3f;
            canvas.drawRoundRect(label_rect, teeth_pix, teeth_pix, p);
        }

        for(int i=0;i<6;i++)
        {
            if(linkedValues[i]!=null) {
                col = value_index % 3;
                //col = 0;
                row = value_index/3;
                canvas.save();
                label_p.setTextSize(label_height*0.7f);
                label_p.setColor(colors[i]);
                p.setAlpha(a);
                label_p.setTextAlign(Paint.Align.LEFT);
                canvas.clipRect(label_x + col * label_width, label_y + row * label_height, label_x + (col + 1) * label_width, label_y + (row + 1) * label_height);
                canvas.drawCircle(label_x + col * label_width+label_height*0.5f,label_y + (row+0.5f) * label_height,label_height*0.33f,label_p);

                //label_p.setColor(0xffffffff);
                label_p.setColor(0xff444444);
                p.setAlpha(a);
                canvas.drawText(valuesName[i],label_x + col * label_width+label_height,label_y + (row+0.8f) * label_height,label_p);
                canvas.restore();
                value_index++;
            }

        }
        canvas.restore();
    }


RectF toolbar_rect = new RectF();
    float bmp_x;
    float bmp_y;
    float bmp_height;


    float []tool_scales=new float[]{1,1,1,1};
    float []tool_scales_d = new float[]{1,1,1,1};
    float scale_dt;
    void drawToolBar(Canvas canvas)
    {

        for(int i=0;i<4;i++)
        {
            scale_dt = tool_scales[i]-tool_scales_d[i];

            if(Math.abs(scale_dt)>0.01f)
            {
                tool_scales_d[i]+=scale_dt*anim_k;
            }else
                tool_scales_d[i] = tool_scales[i];
        }

        canvas.save();
        canvas.translate(toolbar_width*(0.9f-menu_anim),0);
        int a = (int)(menu_anim*255);
        toolbar_rect.left = toolbar_x;
        toolbar_rect.right = w_half;
        toolbar_rect.top = toolbar_y;
        toolbar_rect.bottom = toolbar_y+toolbar_height;
        p.setColor(0xffffffff);
        p.setAlpha(a);
        canvas.drawRoundRect(toolbar_rect,teeth_pix,teeth_pix,p);

        bmp_x = (toolbar_rect.left+toolbar_rect.right)*0.5f;

        bmp_height = toolbar_height*0.25f;
        bmp_y = toolbar_y+bmp_height*0.5f;

        for(int i=0;i<4;i++)
        {
            if(scaled_tools[i]!=null)
            {
                canvas.save();
                canvas.translate(bmp_x,bmp_y+bmp_height*i);
                canvas.scale(tool_scales_d[i],tool_scales_d[i]);
                canvas.drawBitmap(scaled_tools[i],-toolbar_bmp_pix_half,-toolbar_bmp_pix_half,p);
                canvas.restore();
            }
        }

        canvas.restore();
    }


    boolean [] ruler_visible = new boolean[2];
    boolean [] ruler_pressed = new boolean[2];
    float [] ruler_x_ratio = new float[2];
    float [] ruler_x_ratio_f = new float[2];
    float ruler_drag_ratio = 0.09f;
    float [] ruler_alpha = new float[2];

    float ruler_x_pix;
    RectF time_rect = new RectF();

    void drawRuler(Canvas canvas)
    {
        float value;

        float dot;
        int index;
        int index_1;
        float offset;
        for(int i=0;i<2;i++)
        {
            if(ruler_visible[i])
            {
                ruler_alpha[i]+=(255-ruler_alpha[i])*0.35f;
            }else
            {
                ruler_alpha[i]+=(-ruler_alpha[i])*0.35f;
            }

            if(ruler_alpha[i]>253)
                ruler_alpha[i] = 255;
            if(ruler_alpha[i]<5)
                ruler_alpha[i] = 0;
            else {
                p.setColor(0xff444444);
                ruler_x_pix =teeth_pix+ w_range * (ruler_x_ratio[i] -0.5f);
                p.setAlpha((int) ruler_alpha[i]);
                canvas.drawLine(ruler_x_pix, -h_half, ruler_x_pix, h_half-teeth_pix-teeth_pix, p);
                p.setColor(0xffffffff);
                p.setAlpha((int)ruler_alpha[i]);
                canvas.drawCircle(ruler_x_pix,h_half-teeth_pix,teeth_pix,p);
                p.setColor(0xff2ea7e0);
                p.setAlpha((int)ruler_alpha[i]);
                canvas.drawCircle(ruler_x_pix,h_half-teeth_pix,teeth_pix*0.7f,p);

                offset = time_offset_d-options.threshold*ruler_x_ratio[i];
                if(offset<0)
                    offset = 0;

                dot = offset-(int)offset;
                index = (int)offset%BUFFER_SIZE;
                if(index<0)
                    index = -1;

                index_1 = index-1;
                if(index_1<0)
                    index_1+=BUFFER_SIZE;

                p.setTextAlign(Paint.Align.LEFT);
                ruler_x_pix+=teeth_pix*0.3f;
                for(int j=0;j<6;j++)
                {
                    if(linkedValues[j]!=null) {
                        //p.setColor(colors[j]);
                        p.setColor(0xffffffff);

                        //if(index!=index_1)

                        if(index>=0)
                            value = wave_buffer[j][index] * dot + wave_buffer[j][index_1] * (1 - dot);
                        else
                            value = 0;
                            //                        else
//                            value = 0;

                        canvas.drawText(decimalFormat.format(value), ruler_x_pix, value2pix(value) + teeth_number_pix * 0.36f, p);
                    }
                }
            }
        }



        if(ruler_visible[0]&&ruler_visible[1])
        {

            float mid_pix =teeth_pix+ w_range*(ruler_x_ratio[0]+ruler_x_ratio[1]-1)*0.5f;
            float sec = options.threshold*(Math.abs(ruler_x_ratio[1]-ruler_x_ratio[0]))*secPerData;
            String sec_str = decimalFormat.format(sec);
            float left_pix = teeth_pix+ w_range*(ruler_x_ratio[0]-0.5f);
            float right_pix = teeth_pix+ w_range*(ruler_x_ratio[1]-0.5f);
            float padding = 0.3f*teeth_number_pix;
            float dist = w_range*(Math.abs(ruler_x_ratio[1]-ruler_x_ratio[0]));
            float text_pix = sec_str.length()*teeth_number_pix*0.75f+padding*2;
            float text_half_pix = text_pix*0.5f;
            float time_y = h_half-teeth_pix*2;
            float time_text_y = time_y-0.5f*teeth_number_pix;
            p.setTextAlign(Paint.Align.CENTER);
            float t;
            if(right_pix<left_pix)
            {
                t = left_pix;
                left_pix = right_pix;
                right_pix = t;
            }

            if(dist>text_pix) {
                p.setColor(0xffffffff);
                canvas.drawLine(left_pix+padding,time_text_y,mid_pix-text_half_pix,time_text_y,p);
                canvas.drawLine(mid_pix+text_half_pix,time_text_y,right_pix-padding,time_text_y,p);
            }

            p.setColor(0xffffffff);
            time_rect.left = mid_pix-text_half_pix;
            time_rect.right = mid_pix+text_half_pix;
            time_rect.top = time_y-teeth_number_pix;
            time_rect.bottom = time_y;
            canvas.drawRoundRect(time_rect,teeth_number_pix,teeth_number_pix,p);

            p.setColor(0xff000000);
            canvas.drawText(sec_str,mid_pix,h_half-teeth_pix*2.2f,p);
        }

    }



    float secPerData = 0.01f;

    public void setMsPerData(float ms)
    {
        secPerData = ms*0.001f;
    }
    String index2Time(float index)
    {
        return decimalFormat.format(index*secPerData);
    }


    float offset_dt;
    @Override
    public void draw(Canvas canvas) {

        canvas.save();
        canvas.clipRect(rectF);


        if(menu_showing) {
            menu_anim += (1 - menu_anim) * anim_k;
            if(menu_anim>0.99f)
                menu_anim = 1;
        }else {
            menu_anim += -menu_anim * anim_k;
            if(menu_anim<0.01f)
                menu_anim = 0;
        }

        offset_dt = time_offset - time_offset_d;
        if(Math.abs(offset_dt)>0.01)
        {
            time_offset_d += offset_dt*anim_k;
        }else
            time_offset_d = time_offset;


        p.setColor(0xffaaaaaa);
        canvas.drawRoundRect(rectF,teeth_pix,teeth_pix,p);
        drawTeeth(canvas);
        drawWaves(canvas);
        drawRuler(canvas);
        if(menu_anim>0.01) {
            drawLabels(canvas,true);
            drawToolBar(canvas);
        }



//        if(cut!=null) {
//            canvas.scale(0.4f,0.4f);
//            canvas.drawBitmap(cut, 0, 0, p);
//        }
        canvas.restore();
    }


    boolean isInRect(float x,float y,RectF rectF)
    {
        if(rectF==null)
            return false;
        return x > rectF.left && x < rectF.right && y > rectF.top && y < rectF.bottom;
    }
     boolean isOnLabels(Context context)
    {
        if(isInRect(ix,iy,label_rect))
        {
            //(context);
            toyListener.onShowLink(this);
            return true;
        }
        return false;
    }

    Bitmap cut;

    // 截图，在bitmap的canvas上绘制波形，然后保存为文件
    void getPicture()
    {
        Date date = new Date();
        cut = Bitmap.createBitmap((int)w_pix,(int)h_pix, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(cut);
        canvas.translate(w_half,h_half);
        p.setColor(0xffaaaaaa);
        canvas.drawRect(rectF,p);
        drawTeeth(canvas);
        drawWaves(canvas);
        drawRuler(canvas);
        drawLabels(canvas,false);

        String str=DateFormat.format("yyyyMMdd-HH:mm:ss.png",date).toString();
        toyListener.onPicture(IDBitmap.saveBitmap(cut,"调试器截图",str));

        str = DateFormat.format("yyyyMMdd-HH:mm:ss",date).toString();
        File waveFile = IDBitmap.getNewFile("调试器波形",str+".csv");
        if(waveFile!=null) {
            CSVFile csvFile = new CSVFile(waveFile);
            List<List<String>> listList = new ArrayList<>();

            List<float[]> waves = new ArrayList<>();
            List<String> waveName = new ArrayList<>();
            waveName.add("TimeStamp(ms)");
            for (int i = 0; i < 6; i++) {
                if (linkedValues[i] != null) {
                    waveName.add(valuesName[i]);
                    waves.add(extractPoints(i, time_offset_d - options.threshold, time_offset_d, node_data_volume));
                }
            }

            float time = 0;
            float time_grid = node_data_volume;
            if(BlueToothMaster.rxPerSec>0)
                time_grid = 1000/BlueToothMaster.rxPerSec * node_data_volume;


            listList.add(waveName);
            if(waves.size()>0) {
                int length = waves.get(0).length;
                if(length>0)
                {
                    for(int i=0;i<length;i++)
                    {
                        List<String> row = new ArrayList<>();
                        row.add(""+time);
                        time += time_grid;
                        for(int j=0;j<waves.size();j++) {
                            row.add("" + waves.get(j)[length-1-i]);
                        }
                        listList.add(row);
                    }
                }
            }
            csvFile.setValueList(listList);
            csvFile.saveLittle();
        }
//        for(int i=0;i<buttonPairNumber*2;i++) {
//            List<String> row = new ArrayList<>();
//            row.add("");
//            row.add("");
//            row.add("");
//            csvTable.add(row);
//        }

    }



    void toolClicked(int index)
    {
        switch (index)
        {
            case 0:  // 跟随与暂停跟随 最新数据

                if(data_following)
                {
                    data_following = false;
                }else
                {
                    data_following = true;
                    time_offset = time;
                }

                break;
            case 1:  // 截图波形

                getPicture();

                break;
            case 2:  // 左标尺

                if(ruler_visible[0])
                    ruler_visible[0] = false;
                else
                {
                    ruler_visible[0] = true;


                    if(ruler_visible[1])
                        ruler_x_ratio[0] = (ruler_x_ratio[1])*0.5f;
                    else
                        ruler_x_ratio[0] = 0.5f;

                }
                break;
            case 3:  // 右标尺
                if(ruler_visible[1])
                    ruler_visible[1] = false;
                else
                {
                    ruler_visible[1] = true;
                    if(ruler_visible[0])

                        ruler_x_ratio[1] = (1+ruler_x_ratio[0])*0.5f;
                    else
                        ruler_x_ratio[1] = 0.5f;

                }
                break;
        }
    }

    boolean isOnTools()
    {
        if(isInRect(ix,iy,toolbar_rect))
        {

            final int i = (int)((iy-toolbar_rect.top)*4/(toolbar_rect.bottom-toolbar_rect.top));
            if(i>=0&&i<4)
            {
                tool_scales[i] = 0.7f;
                toolClicked(i);
                Thread thread = new Thread(){
                    @Override
                    public void run() {

                        try {
                            sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        tool_scales[i] = 1;
                    }
                };
                thread.start();
            }
            return true;
        }
        return false;
    }

    float ix,iy;
    @Override
    public void clicked(Context context) {

        if(menu_showing) {
            ix = (rx - 0.5f) * w_pix;
            iy = (ry - 0.5f) * h_pix;
            if (!isOnLabels(context)&&!isOnTools()) {
                menu_showing = !menu_showing;
            }
        }else
            menu_showing = true;
    }


    int drag_state = 0;
    float drag_mx,drag_my;

    float RULER_MAX = 1;
    float RULER_MIN = 0;
    @Override
    public void dragged() {

        if(!zoomed) {

            for(int i=0;i<2;i++) {
                if (ruler_visible[i] && ruler_pressed[i]) {
                    ruler_x_ratio[i] = ruler_x_ratio_f[i] + (rx - f_drag_x);
                    if (ruler_x_ratio[i] > RULER_MAX)
                        ruler_x_ratio[i] = RULER_MAX;
                    if (ruler_x_ratio[i] < RULER_MIN)
                        ruler_x_ratio[i] = RULER_MIN;
                    return;
                }
            }

            if (drag_state == 0) {

                drag_mx = ControlView.pix2MM(ax);
                drag_my = ControlView.pix2MM(ay);


                if(Math.abs(drag_mx-f_drag_mx)>2)
                    drag_state+=1;

                if(Math.abs(drag_my-f_drag_my)>2)
                    drag_state+=2;

                if(drag_state==0)
                {
                    if(Math.abs(drag_my-f_drag_my)>Math.abs(drag_mx-f_drag_mx))
                        drag_state = 2;
                    else
                        drag_state = 1;
                }
            }

            float value_d = (ry - f_drag_y) * (f_value_a - f_value_b);
            float time_d = (rx - f_drag_x) * options.threshold;

            if(drag_state>=2)
            {
                options.on_value = f_value_a + value_d;
                options.off_value = f_value_b + value_d;
            }

            if(drag_state==1||drag_state==3) {
                time_offset = f_time_off + time_d;


                if(time_offset<time-(BUFFER_SIZE-options.threshold))
                    time_offset = time-(BUFFER_SIZE-options.threshold);
                if(time_offset>time) {
                    time_offset = time;
                    data_following = true;
                }
                if(time_offset<time-1)
                data_following = false;
            }
        }

    }
    boolean zoomed = false;
    @Override
    public void released() {

        if(time_offset>time)
            time_offset = time;
        if(time_offset<0)
            time_offset = 0;
        zoomed = false;
    }

    float f_drag_x,f_drag_y;

    float f_value_a,f_value_b,f_time_off;
    float f_time_points;
    float f_value_range;

    float f_drag_mx,f_drag_my;
    @Override
    public void pressed() {
        f_drag_y = (ry);
        f_drag_x =(rx);
        f_drag_mx = ControlView.pix2MM(ax);
        f_drag_my = ControlView.pix2MM(ay);

        drag_state = 0;
        f_value_b = options.off_value;
        f_value_a = options.on_value;
        f_time_off = time_offset;

        for(int i=0;i<2;i++) {
            ruler_pressed[i] = false;
            if(ruler_visible[i]) {
                if (Math.abs(ruler_x_ratio[i] - rx) < ruler_drag_ratio) {
                    ruler_pressed[i] = true;
                    ruler_x_ratio_f[i] = ruler_x_ratio[i];
                }
            }
        }

    }

    @Override
    public void zoom_started() {
        zoomed = true;
        f_time_points = options.threshold;
        f_value_range = options.on_value-options.off_value;
    }

    @Override
    public void zoomed(float sx, float sy) {
        if(zoomMode==1) {
            options.threshold = f_time_points/sx;

            if(options.threshold<20)
                options.threshold = 20;
            if(options.threshold>5000)
                options.threshold=5000;

            if(time_offset<time-(BUFFER_SIZE-options.threshold))
                time_offset = time-(BUFFER_SIZE-options.threshold);

        }else if(zoomMode==2)
        {
            float mid  = (options.on_value+options.off_value)*0.5f;

            options.on_value = mid+f_value_range*0.5f/sy;
            options.off_value = mid-f_value_range*0.5f/sy;

        }
    }

    float ph=0;

    float CIRCLE_LENGTH = BUFFER_SIZE*10;


    @Override
    public void onRxData() {
        int index;

        //Log.w(TAG, "onRxData: "+BlueToothMaster.rxPerSec);

        ph+=0.05f;
        if(data_recording) {

            for (int i = 0; i < 6; i++) {
                if(linkedValues[i]!=null) {
                    index = time%BUFFER_SIZE;
                    wave_buffer[i][index] = linkedValues[i].getFloat();
                    //wave_buffer[i][index] = 500*(float)Math.sin(ph*(5+i)/5);
                }
            }
            time++;

            if(time>CIRCLE_LENGTH)
                time-=CIRCLE_LENGTH;

            if(data_following)
                time_offset = time;
            else
            {

                if(time_offset<time-(BUFFER_SIZE-options.threshold))
                    time_offset = time-(BUFFER_SIZE-options.threshold);

//                if(time_offset<time-100)
//                    time_offset = time-100;
            }

        }
        //time_offset+=1;
    }
}
